$input v_texcoord0, v_color0, v_wnormal, v_wpos, v_view

#include <bgfx_shader.sh>
#define MAX_LIGHTS 8

SAMPLER2D(s_mainTexture, 0);
SAMPLER2D(s_specularTexture, 1);
// x: 1为纯色渲染，-1为表面纹理；y: 是否有镜面光纹理；z: 光滑度(反光度)
uniform vec4 u_materialParams;
// 环境光颜色
uniform vec4 u_ambientColor;
// 光源参数, 对应下面的Light结构体
uniform vec4 u_lights[MAX_LIGHTS * 6];
// 光源数量
uniform vec4 u_lightCount;

struct Light {
    vec4 params;          // x: 类型 (0: 方向光, 1: 点光源, 2: 聚光灯)， y: 强度
    vec4 position;      // 位置 (点光源和聚光灯使用)
    vec4 direction;     // 方向 (方向光和聚光灯使用)
    vec4 color;         // 颜色
    vec4 attenuation;   // 衰减参数 (x: 常数, y: 线性, z: 二次, w: 范围)
    vec4 spotParams;    // 聚光灯参数 (x: 内角余弦, y: 外角余弦, z: 衰减)
};

// 函数声明
vec3 calculateDirectionalLight(Light light, vec3 normal, vec3 viewDir, vec3 diffuseColor, float specularStrength, float shininess);
vec3 calculatePointLight(Light light, vec3 normal, vec3 fragPos, vec3 viewDir, vec3 diffuseColor, float specularStrength, float shininess);
vec3 calculateSpotLight(Light light, vec3 normal, vec3 fragPos, vec3 viewDir, vec3 diffuseColor, float specularStrength, float shininess);
float calculateAttenuation(Light light, float distance);

void main()
{
    // 法线
    vec3 normal = v_wnormal;
    // 世界坐标系中的位置
    vec3 pos = v_wpos;
    // 视图方向
    vec3 viewDir = v_view;

    // 获取材质颜色 - 根据是否使用纹理选择颜色来源
    vec4 mainColor;
    vec3 diffuseColor;
    float specularStrength = 0.5;
    float shininess = u_materialParams.z;
    if (u_materialParams.x > 0.0) {
        // 使用纹理
        mainColor = texture2D(s_mainTexture, v_texcoord0);
    } else {
        // 使用颜色
        mainColor = v_color0;
    }
    diffuseColor = mainColor.rgb;
    if (u_materialParams.y > 0.0) {
        specularStrength = texture2D(s_specularTexture, v_texcoord0).r;
    }

    // 初始颜色为环境光
    vec3 result = u_ambientColor.rgb * diffuseColor * u_ambientColor.a;
    // 处理每个光源
    int lightCount = int(u_lightCount.x);
    for (int i = 0; i < lightCount; i++)
    {
        Light light;
        int base = i * 6;
        light.params = u_lights[base];
        light.position = u_lights[base + 1];
        light.direction = u_lights[base + 2];
        light.color = u_lights[base + 3];
        light.attenuation = u_lights[base + 4];
        light.spotParams = u_lights[base + 5];

        int type = int(light.params.x);
        if (type == 0) // 方向光
        {
            result += calculateDirectionalLight(light, normal, viewDir, diffuseColor, specularStrength, shininess);
        }
        else if (type == 1) // 点光源
        {
            result += calculatePointLight(light, normal, pos, viewDir, diffuseColor, specularStrength, shininess);
        }
        else if (type == 2) // 聚光灯
        {
            result += calculateSpotLight(light, normal, pos, viewDir, diffuseColor, specularStrength, shininess);
        }
    }

    gl_FragColor = vec4(result, mainColor.a);
}

// 计算方向光
vec3 calculateDirectionalLight(Light light, vec3 normal, vec3 viewDir, vec3 diffuseColor, float specularStrength, float shininess)
{
    vec3 lightDir = normalize(-light.direction.xyz);

    // 漫反射
    float diff = max(dot(normal, lightDir), 0.0);
    vec3 diffuse = light.color.rgb * light.params.y * diff * diffuseColor * light.color.a;

    // 镜面反射
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
    vec3 specular = light.color.rgb * light.params.y * spec * specularStrength * light.color.a;

    return diffuse + specular;
}

// 计算点光源
vec3 calculatePointLight(Light light, vec3 normal, vec3 fragPos, vec3 viewDir, vec3 diffuseColor, float specularStrength, float shininess)
{
    vec3 lightDir = normalize(light.position.xyz - fragPos);
    float distance = length(light.position.xyz - fragPos);

    // 检查是否在范围内
    if (distance > light.attenuation.w)
        return vec3(0.0, 0.0, 0.0);

    // 计算衰减
    float attenuation = calculateAttenuation(light, distance);

    // 漫反射
    float diff = max(dot(normal, lightDir), 0.0);
    vec3 diffuse = light.color.rgb * light.params.y * diff * diffuseColor * light.color.a;

    // 镜面反射
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
    vec3 specular = light.color.rgb * light.params.y * spec * specularStrength * light.color.a;

    return (diffuse + specular) * attenuation;
}

// 计算聚光灯
vec3 calculateSpotLight(Light light, vec3 normal, vec3 fragPos, vec3 viewDir, vec3 diffuseColor, float specularStrength, float shininess)
{
    vec3 lightDir = normalize(light.position.xyz - fragPos);
    float distance = length(light.position.xyz - fragPos);

    // 检查是否在范围内
    if (distance > light.attenuation.w)
        return vec3(0.0, 0.0, 0.0);

    // 计算衰减
    float attenuation = calculateAttenuation(light, distance);

    // 聚光灯强度计算
    float theta = dot(lightDir, normalize(-light.direction.xyz));
    float epsilon = light.spotParams.x - light.spotParams.y;
    float intensity = clamp((theta - light.spotParams.y) / epsilon, 0.0, 1.0);
    intensity = pow(intensity, light.spotParams.z);

    // 漫反射
    float diff = max(dot(normal, lightDir), 0.0);
    vec3 diffuse = light.color.rgb * light.params.y * diff * diffuseColor * light.color.a;

    // 镜面反射
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
    vec3 specular = light.color.rgb * light.params.y * spec * specularStrength * light.color.a;

    return (diffuse + specular) * attenuation * intensity;
}

// 计算衰减
float calculateAttenuation(Light light, float distance)
{
    return 1.0 / (light.attenuation.x +
                  light.attenuation.y * distance +
                  light.attenuation.z * distance * distance);
}